package com.scut.filedownloader.core.recorder;

import android.content.SharedPreferences;

import androidx.annotation.NonNull;


/**
 * 记录下载条目内的元数据
 * 包括URL：url:String
 * 文件保存的路径名：pathname:String
 * 文件大小： fileSize: long
 * 文件分块数： blockCount: long (包括尾部块)
 * 文件分块大小： blockSize:int
 * 文件块已经下载的信息：block_%blockNumber%: long (根据文件分块数决定块的范围)
 * 尾部长度：　tailLength: long(可计算得出，无需记录）
 */
public class DownloadRecorder {

    //private String filename=null; //记录文件信息
    private SharedPreferences downloadInfo;
    private SharedPreferences.Editor editor;
    private long fileSize=0;
    private int blockSize=0;
    private long blockCount=0;
    //private boolean recordChanged=false;

    public DownloadRecorder(@NonNull SharedPreferences info){
        this.downloadInfo=info;
        editor=info.edit();

        fileSize=getFileSize();
        blockCount=getBlockCount();
        blockSize=getBlockSize();
    }

    /**
     * 记录文件路径，这是表示一个下载任务的主码
     * @param pathname
     */
    public void recordPath(String pathname){
        editor.putString("pathname",pathname);

    }

    /**
     * 获取该下载条目的文件名，如果存在
     * @return 不存在返回null
     */
    public String getFileName(){
        String pathname=getPathName();
        if(pathname!=null){
            final int last_index=pathname.lastIndexOf('/');
            if(last_index==-1){
                return pathname;
            }
            else{
                return pathname.substring(last_index+1);
            }
        }
        return null;
    }

    /**
     * 判断该下载信息记录器是否对应了一个空的记录项，该方法可能会进行IO操作，目的为了检索必要的有效字段。
     * @return
     */
    public boolean isEmptyEntry(){
        return !downloadInfo.contains("fileSize")&&!downloadInfo.contains("blockCount")&&!downloadInfo.contains("url")&&!downloadInfo.contains("pathname");
    }

    /**
     * 记录下载url源地址
     * @param url
     */
    public void recordURL(String url){
        editor.putString("url",url);

    }

    /**
     * 记录所下载的文件的大小
     * @param fileSize 以字节为单位
     */
    public void recordFileSize(long fileSize){
        editor.putLong("fileSize",fileSize);
        this.fileSize=fileSize;

    }

    /**
     * 标记文件是否下载完成，调用该方法后还需要再调用{@link #commit()},保证操作有效
     * @param finished
     */
    public void markFinished(boolean finished){
        editor.putBoolean("finished",finished);
    }

    /**
     * 记录文件分块数量
     * @param blockCount
     */
    public void recordBlockCount(long blockCount){
        editor.putLong("blockCount",blockCount);
        this.blockCount=blockCount;
    }

    /**
     * 记录单个分块的大小
     * @param blockSize 字节为单位
     */
    public void recordBlockSize(int blockSize){
        editor.putInt("blockSize",blockSize);
        this.blockSize=blockSize;
    }

    /**
     * 检查文件块编号是否在 1 ~ blockCount之间
     * @param progress
     * @param block_number
     */
    public void recordBlockInfo(long progress,long block_number){
        //check
        if(block_number>0&&block_number<=blockCount){
            StringBuilder stringBuilder=new StringBuilder("block_");
            stringBuilder.append(block_number);
            if(block_number==blockCount) { //this is a tail block
                long tailLength = fileSize % blockSize;
                progress= Math.min(progress, tailLength); //limit its range
            }
            else{
                progress=Math.min(progress,blockSize);
            }
            editor.putLong(stringBuilder.toString(),progress);
        }

    }

    /**
     * 从记录中获取下载的url
     * @return 如果没有则为null
     */
    public String getUrl(){
        if(downloadInfo.contains("url")){
            return downloadInfo.getString("url","");
        }
        return null;
    }

    /**
     * 从记录中获取文件存储路径
     * @return 如果没有该记录，则为null
     */
    public String getPathName(){
        if(downloadInfo.contains("pathname")){
            return downloadInfo.getString("pathname","");
        }
        return null;
    }

    /**
     * 获取文件大小
     * @return 如果没有该字段，则返回-1
     */
    public long getFileSize(){
        if(downloadInfo.contains("fileSize")){
            return downloadInfo.getLong("fileSize",-1);
        }
        return -1;
    }

    /**
     * 获取该下载条目所指任务的完成情况，如果完成则为true
     * @return
     */
    public boolean getFinishedState(){
        if(downloadInfo.contains("finished")){
            return downloadInfo.getBoolean("finished",false);
        }
        return false;
    }

    /**
     * 获取分块数量，如果字段无效则返回-1
     * @return
     */
    public long getBlockCount(){
        if(downloadInfo.contains("blockCount")){
            return downloadInfo.getLong("blockCount",-1);
        }
        return -1;

    }

    /**
     * 获取分块大小
     * @return 如果字段无效则为-1
     */
    public int getBlockSize(){
        if(downloadInfo.contains("blockSize")){
            return downloadInfo.getInt("blockSize",-1);
        }
        return -1;
    }

    /**
     * 获取该任务总进度情况, 该方法会执行较多IO操作，所以没有使用
     * @return
     */
    public long getProgress(){
        final int block_count= (int) getBlockCount();
        //search
        long sum=0L;
        for(int i=1;i<=block_count;i++){
            long block_valid_length= getBlockInfo(i);
            block_valid_length= block_valid_length==-1 ? 0L : block_valid_length;
            sum+=block_valid_length;
        }
        return sum;
    }

    /**
     * 给定块编号，获取块的下载进度信息，注意尾部块的大小不为blockSize
     * 给定编号超出范围则为-1，否则默认值为0
     * @param block_number
     * @return
     */
    public long getBlockInfo(int block_number){
        if(block_number>0&&block_number<=blockCount){
            StringBuilder blockNameBuilder=new StringBuilder("block_");
            blockNameBuilder.append(block_number);
            if(downloadInfo.contains(blockNameBuilder.toString())) {
                return downloadInfo.getLong(blockNameBuilder.toString(), 0L);
            }
        }
        return -1;
    }

    /**
     * 周期性执行此函数，更新数据信息到永久存储区,这里打算将该函数附加到工作线程中执行
     */
    public void commit(){
        editor.commit();
    }


}
